package com.define.ssh.dao.impl;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.impl.CriteriaImpl.OrderEntry;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.transform.ResultTransformer;
import org.springframework.util.Assert;
import org.hibernate.Query;

import com.define.ssh.dao.BaseDao;
import com.define.ssh.model.BaseEntity;
import com.define.ssh.util.Pager;
import com.define.ssh.util.ReflectionUtil;

/**
 * Dao实现类 - 基类 aaaa
 */

public class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {

	private static final String ORDER_LIST_PROPERTY_NAME = "orderList";// "排序"属性名称
	private static final String CREATE_DATE_PROPERTY_NAME = "createDate";// "创建日期"属性名称

	private Class<T> entityClass;
	protected SessionFactory sessionFactory;

	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		final Class c = getClass();
		final Type type = c.getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			final Type[] parameterizedType = ((ParameterizedType) type)
					.getActualTypeArguments();
			this.entityClass = (Class<T>) parameterizedType[0];
		}
	}

	@Resource(name = "sessionFactory")
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	@SuppressWarnings("unchecked")
	public T get(PK id) {
		Assert.notNull(id, "id is required");
		return (T) getSession().get(entityClass, id);
	}

	@Override
	@SuppressWarnings("unchecked")
	public T load(PK id) {
		Assert.notNull(id, "id is required");
		return (T) getSession().load(entityClass, id);
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<T> getAllList() {
		final ClassMetadata classMetadata = sessionFactory
				.getClassMetadata(entityClass);
		String hql;
		if (ArrayUtils.contains(classMetadata.getPropertyNames(),
				ORDER_LIST_PROPERTY_NAME)) {
			hql = "from " + entityClass.getName()
					+ " as entity order by entity." + ORDER_LIST_PROPERTY_NAME
					+ " desc";
		} else {
			hql = "from " + entityClass.getName();
		}
		return getSession().createQuery(hql).list();
	}

	@Override
	public List<T> getAllListByParameter(HashMap<String, Object> hashMap) {
		final ClassMetadata classMetadata = sessionFactory
				.getClassMetadata(entityClass);
		String hql = "from " + entityClass.getName() + " as entity where 1=1 ";
		if (hashMap != null) {
			final Iterator it = hashMap.entrySet().iterator();
			while (it.hasNext()) {
				final Map.Entry pairs = (Map.Entry) it.next();
				hql += " and entity." + pairs.getKey().toString() + "='"
						+ pairs.getValue().toString() + "'";
			}
		}
		final Query query = getSession().createQuery(hql);
		return query.list();
	}
	
	
	
	/**
	 * 
	 * @param query
	 * @return list
	 */
	@Override
	public List findByQuery(final String query) {
		final Query query1 = getSession().createSQLQuery(query);
		List list=query1.list();
		return list;
	}

	/**
	 * 
	 * @param query
	 * @param parameter
	 * @return list
	 */
	@Override
	public List findByQuery(final String querySql, final Object parameter) {
		final Query query = getSession().createSQLQuery(querySql);
		query.setParameter(0, parameter);
		return query.list();
	}

	/**
	 * @param query
	 * @param parameter
	 * @return
	 */
	@Override
	public List findByQuery(final String querySql, final Object[] parameter) {
		final Query query = getSession().createSQLQuery(querySql);
		for (int i = 0; i < parameter.length; i++) {
			query.setParameter(i, parameter[i]);
		}
		return query.list();
	}

	@Override
	public List<T> getAllListByParameter(HashMap<String, Object> hashMap,
			String orderByName) {
		final ClassMetadata classMetadata = sessionFactory
				.getClassMetadata(entityClass);
		String hql = "from " + entityClass.getName() + " as entity where 1=1 ";
		if (hashMap != null) {
			final Iterator it = hashMap.entrySet().iterator();
			while (it.hasNext()) {
				final Map.Entry pairs = (Map.Entry) it.next();
				hql += " and entity." + pairs.getKey().toString() + "='"
						+ pairs.getValue().toString() + "'";
			}
		}
		hql += " order by " + orderByName + " desc";
		final Query query = getSession().createQuery(hql);
		return query.list();
	}

	@Override
	public Long getTotalCount() {
		final String hql = "select count(*) from " + entityClass.getName();
		return (Long) getSession().createQuery(hql).uniqueResult();
	}

	@Override
	@SuppressWarnings("unchecked")
	public PK save(T entity) {
		Assert.notNull(entity, "entity is required");
		if (entity instanceof BaseEntity) {
			try {
				final Method method = entity.getClass().getMethod(
						BaseEntity.ON_SAVE_METHOD_NAME);
				method.invoke(entity);
				return (PK) getSession().save(entity);
			} catch (final Exception e) {
				e.printStackTrace();
				return null;
			}
		} else {
			return (PK) getSession().save(entity);
		}
	}

	@Override
	public void update(T entity) {
		Assert.notNull(entity, "entity is required");
		if (entity instanceof BaseEntity) {
			try {
				final Method method = entity.getClass().getMethod(
						BaseEntity.ON_UPDATE_METHOD_NAME);
				method.invoke(entity);
				getSession().update(entity);
			} catch (final Exception e) {
				e.printStackTrace();
			}
		} else {
			getSession().update(entity);
		}
	}

	@Override
	public void delete(T entity) {
		Assert.notNull(entity, "entity is required");
		getSession().delete(entity);
	}

	@Override
	@SuppressWarnings("unchecked")
	public void delete(PK id) {
		Assert.notNull(id, "id is required");
		final T entity = (T) getSession().load(entityClass, id);
		getSession().delete(entity);
	}

	@Override
	@SuppressWarnings("unchecked")
	public void delete(PK[] ids) {
		Assert.notEmpty(ids, "ids must not be empty");
		for (final PK id : ids) {
			final T entity = (T) getSession().load(entityClass, id);
			getSession().delete(entity);
		}
	}

	@Override
	public void flush() {
		getSession().flush();
	}

	@Override
	public void evict(Object object) {
		Assert.notNull(object, "object is required");
		getSession().evict(object);
	}

	@Override
	public void clear() {
		getSession().clear();
	}

	@Override
	public Pager findPager(Pager pager) {
		final Criteria criteria = getSession().createCriteria(entityClass);
		return findPager(pager, criteria);
	}

	@Override
	public Pager findPager(Pager pager, Criterion... criterions) {
		final Criteria criteria = getSession().createCriteria(entityClass);
		for (final Criterion criterion : criterions) {
			criteria.add(criterion);
		}
		return findPager(pager, criteria);
	}

	@Override
	public Pager findPager(Pager pager, Order... orders) {
		final Criteria criteria = getSession().createCriteria(entityClass);
		for (final Order order : orders) {
			criteria.addOrder(order);
		}
		return findPager(pager, criteria);
	}

	@Override
	public Pager findPager(Pager pager, Criteria criteria) {
		Assert.notNull(pager, "pager is required");
		Assert.notNull(criteria, "criteria is required");

		final Integer pageNumber = pager.getPageNumber();
		final Integer pageSize = pager.getPageSize();
		final String searchBy = pager.getSearchBy();
		final String keyword = pager.getKeyword();
		final String orderBy = pager.getOrderBy();
		final Pager.Order order = pager.getOrder();
		if (StringUtils.isNotEmpty(searchBy) && StringUtils.isNotEmpty(keyword)) {
			if (searchBy.contains(".")) {
				final String alias = StringUtils.substringBefore(searchBy, ".");
				criteria.createAlias(alias, alias);
			}
			criteria.add(Restrictions.like(searchBy, "%" + keyword + "%"));
		}

		/********************* 查询条件的存放集合值 20130603 by add hcy start **********************************/
		final Map<String, Object> searchMap = pager.getSearchMap();
		if (searchMap != null) {
			final Iterator it = searchMap.entrySet().iterator();
			while (it.hasNext()) {
				final Map.Entry pairs = (Map.Entry) it.next();
				if (pairs.getValue() instanceof Integer) {
					criteria.add(Restrictions.eq(pairs.getKey().toString(),
							pairs.getValue()));
				} else if (pairs.getValue() instanceof Long) {
					criteria.add(Restrictions.eq(pairs.getKey().toString(),
							pairs.getValue()));
				} else {
					criteria.add(Restrictions.like(pairs.getKey().toString(),
							"%" + pairs.getValue().toString() + "%"));
				}
			}
		}
		/********************* 查询条件的存放集合值 20130603 by add hcy end **********************************/

		pager.setTotalCount(criteriaResultTotalCount(criteria));

		if (StringUtils.isNotEmpty(orderBy) && order != null) {
			if (order == Pager.Order.asc) {
				criteria.addOrder(Order.asc(orderBy));
			} else {
				criteria.addOrder(Order.desc(orderBy));
			}
		}

		final ClassMetadata classMetadata = sessionFactory
				.getClassMetadata(entityClass);
		if (!StringUtils.equals(orderBy, ORDER_LIST_PROPERTY_NAME)
				&& ArrayUtils.contains(classMetadata.getPropertyNames(),
						ORDER_LIST_PROPERTY_NAME)) {
			criteria.addOrder(Order.asc(ORDER_LIST_PROPERTY_NAME));
			criteria.addOrder(Order.desc(CREATE_DATE_PROPERTY_NAME));
			if (StringUtils.isEmpty(orderBy) || order == null) {
				pager.setOrderBy(ORDER_LIST_PROPERTY_NAME);
				pager.setOrder(Pager.Order.asc);
			}
		} else if (!StringUtils.equals(orderBy, CREATE_DATE_PROPERTY_NAME)
				&& ArrayUtils.contains(classMetadata.getPropertyNames(),
						CREATE_DATE_PROPERTY_NAME)) {
			criteria.addOrder(Order.desc(CREATE_DATE_PROPERTY_NAME));
			if (StringUtils.isEmpty(orderBy) || order == null) {
				pager.setOrderBy(CREATE_DATE_PROPERTY_NAME);
				pager.setOrder(Pager.Order.desc);
			}
		}

		criteria.setFirstResult((pageNumber - 1) * pageSize);
		criteria.setMaxResults(pageSize);

		pager.setResult(criteria.list());
		return pager;
	}

	// 获取Criteria查询数量
	@SuppressWarnings("unchecked")
	private int criteriaResultTotalCount(Criteria criteria) {
		Assert.notNull(criteria, "criteria is required");

		int criteriaResultTotalCount = 0;
		try {
			final CriteriaImpl criteriaImpl = (CriteriaImpl) criteria;

			final Projection projection = criteriaImpl.getProjection();
			final ResultTransformer resultTransformer = criteriaImpl
					.getResultTransformer();
			final List<OrderEntry> orderEntries = (List) ReflectionUtil
					.getFieldValue(criteriaImpl, "orderEntries");
			ReflectionUtil.setFieldValue(criteriaImpl, "orderEntries",
					new ArrayList());

			final Integer totalCount = ((Long) criteriaImpl.setProjection(
					Projections.rowCount()).uniqueResult()).intValue();
			if (totalCount != null) {
				criteriaResultTotalCount = totalCount;
			}

			criteriaImpl.setProjection(projection);
			if (projection == null) {
				criteriaImpl
						.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
			}
			if (resultTransformer != null) {
				criteriaImpl.setResultTransformer(resultTransformer);
			}
			ReflectionUtil.setFieldValue(criteriaImpl, "orderEntries",
					orderEntries);
		} catch (final Exception e) {

		}
		return criteriaResultTotalCount;
	}

	/**
	 * 返回符合条件的记录列表
	 * 
	 * @param dc
	 * @return list
	 */
	@Override
	public List findByCriteria(final DetachedCriteria dc) {
		final Session session = getSession();
		final Criteria criteria = dc.getExecutableCriteria(session);
		criteria.setProjection(null);
		criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		return criteria.list();
	}

	/**
	 * 搜索指定数量的数据
	 * 
	 * @param dc
	 * @param count
	 * @return
	 */
	@Override
	public List findByCriteria(final DetachedCriteria dc, final int count) {
		final Session session = getSession();
		final Criteria criteria = dc.getExecutableCriteria(session);
		// criteria.setProjection(null);
		criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY)
				.setMaxResults(count);
		return criteria.list();

	}
	
	/**
	 * 取得最新更新时间
	 * @param table
	 * @return
	 */
	public  Date getUpdateTime(String table)
	{
		final String sql = "SELECT MAX(update_time) AS update_time FROM "+table;
		return ((Date) getSession().createSQLQuery(sql).uniqueResult());
		
	}
	
	/**
	 * 取得最新更新时间
	 * @param table
	 * @return
	 */
	public  Date getUpdateFiled(String table,String filed)
	{
		final String sql = "SELECT MAX("+filed+") AS update_time FROM "+table;
		System.out.println("sql=="+sql);
		return ((Date) getSession().createSQLQuery(sql).uniqueResult());
		
	}
}